package com.msb.search.service.impl;

import com.msb.common.constart.RabbitMQConstants;
import com.msb.common.enums.ExceptionEnums;
import com.msb.common.exception.ApiException;
import com.msb.common.exception.GraceException;
import com.msb.common.model.StandardReport;
import com.msb.search.service.SearchService;
import com.msb.search.utils.SearchUtils;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;

/**
 * @Author: lmf
 * @Create: 2025/3/19 21:21
 * @module
 */
@Service
@Slf4j
public class ElasticSearchServiceImpl implements SearchService {
    /**
     * 添加成功的状态
     */
    private final String CREATED = "created";

    @Resource
    private RestHighLevelClient restHighLevelClient;

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Override
    public boolean exists(String index, String id) throws IOException {
        // 构建GetRequest，查看索引是否存在
        GetRequest request = new GetRequest();

        // 指定索引信息，还有文档id
        request.index(index).id(id);

        // 基于restHighLevelClient将查询指定id的文档是否存在的请求投递过去。
        return restHighLevelClient.exists(request, RequestOptions.DEFAULT);
    }

    @Override
    public void update(String index, String id, Map<String, Object> doc) throws IOException {
        //1、基于exists方法，查询当前文档是否存在
        if (!exists(index, id)) {
            // 当前文档不存在
            StandardReport report = SearchUtils.getReport();
            if (report.getReUpdate()) {
                // 第二次获取投递的消息，到这已经是延迟20s了。
                log.error("【文档不存在-搜索模块添加失败】 index={},id={},json={}", index, id, doc);
                return;
            }

            // 第一次投递，可以再次将消息仍会MQ中
            // 开始第二次消息的投递了
            report.setReUpdate(true);
            rabbitTemplate.convertAndSend(RabbitMQConstants.SMS_GATEWAY_NORMAL_QUEUE, report);
            SearchUtils.removeReport();
            return;
        }
        UpdateRequest updateRequest = new UpdateRequest();
        updateRequest.index(index).id(id).doc(doc);
        UpdateResponse update = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);

        SearchUtils.removeReport();
        final String UPDATED = "updated";
        if (!update.getResult().getLowercase().equals(UPDATED)) {
            log.error("【搜索模块更新失败】 index={},id={},json={}", index, id, doc);
            GraceException.display(ExceptionEnums.SEARCH_UPDATE_ERROR);
        }

        log.info("【搜索模块更新成功】 index={},id={},json={}", index, id, doc);
    }

    @Override
    public Map<String, Object> findSmsByParameters(Map<String, Object> parameters) throws IOException {
        SearchRequest request = new SearchRequest();

        //2、封装查询条件
        //2.1 参数全部取出来
        Object fromObj = parameters.get("from");
        Object sizeObj = parameters.get("size");
        Object contentObj = parameters.get("content");
        Object mobileObj = parameters.get("mobile");
        Object startTimeObj = parameters.get("starttime");
        Object stopTimeObj = parameters.get("stoptime");
        Object clientIDObj = parameters.get("clientID");

        //2.2 clientID需要单独操作一下。
        List<Long> clientIDList = null;
        if (clientIDObj instanceof List) {
            // 传递的是一个集合
            clientIDList = (List<Long>) clientIDObj;
        } else if (!ObjectUtils.isEmpty(clientIDObj)) {
            // 传递的是一个数字
            clientIDList = Collections.singletonList(Long.parseLong(clientIDObj + ""));
        }

        //2.3 条件封装
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        // ========================封装查询条件到boolQuery========================================
        //2.3.1、关键字
        if (!ObjectUtils.isEmpty(contentObj)) {
            boolQuery.must(QueryBuilders.matchQuery("text", contentObj));
            // 高亮。设置给sourceBuilder
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.field("text");
            highlightBuilder.preTags("<span style='color: red'>");
            highlightBuilder.postTags("</span>");
            highlightBuilder.fragmentSize(100);
            sourceBuilder.highlighter(highlightBuilder);
        }

        //2.3.2、手机号
        if (!ObjectUtils.isEmpty(mobileObj)) {
            boolQuery.must(QueryBuilders.prefixQuery("mobile", (String) mobileObj));
        }

        //2.3.3、开始时间
        if (!ObjectUtils.isEmpty(startTimeObj)) {
            boolQuery.must(QueryBuilders.rangeQuery("sendTime").gte(startTimeObj));
        }

        //2.3.4、结束时间
        if (!ObjectUtils.isEmpty(stopTimeObj)) {
            boolQuery.must(QueryBuilders.rangeQuery("sendTime").lte(stopTimeObj));
        }

        //2.3.5、客户id
        if (clientIDList != null) {
            boolQuery.must(QueryBuilders.termsQuery("clientId", clientIDList.toArray(new Long[]{})));
        }

        //2.3.6 分页查询
        sourceBuilder.from(Integer.parseInt(fromObj + ""));
        sourceBuilder.size(Integer.parseInt(sizeObj + ""));

        // ========================封装查询条件到boolQuery========================================
        sourceBuilder.query(boolQuery);
        request.source(sourceBuilder);

        //3、执行查询
        SearchResponse resp = restHighLevelClient.search(request, RequestOptions.DEFAULT);

        //4、封装数据
        long total = resp.getHits().getTotalHits().value;
        List<Map> rows = new ArrayList<>();
        for (SearchHit hit : resp.getHits().getHits()) {
            Map<String, Object> row = hit.getSourceAsMap();
            List sendTime = (List) row.get("sendTime");
            String sendTimeStr = listToDateString(sendTime);
            row.put("sendTimeStr", sendTimeStr);
            row.put("corpname", row.get("sign"));
            // 高亮结果的处理
            HighlightField highlightField = hit.getHighlightFields().get("text");
            if (highlightField != null) {
                String textHighLight = highlightField.getFragments()[0].toString();
                row.put("text", textHighLight);
            }
            rows.add(row);
        }
        //5、返回数据
        Map<String, Object> result = new HashMap<>();
        result.put("total", total);
        result.put("rows", rows);
        return result;
    }

    private String listToDateString(List sendTime) {
        String year = sendTime.get(0) + "";
        Integer monthInt = (Integer) sendTime.get(1);
        Integer dayInt = (Integer) sendTime.get(2);
        Integer hourInt = (Integer) sendTime.get(3);
        Integer minuteInt = (Integer) sendTime.get(4);
        Integer secondInt = (Integer) sendTime.get(5);

        String month = monthInt / 10 == 0 ? "0" + monthInt : monthInt + "";
        String day = dayInt / 10 == 0 ? "0" + dayInt : dayInt + "";
        String hour = hourInt / 10 == 0 ? "0" + hourInt : hourInt + "";
        String minute = minuteInt / 10 == 0 ? "0" + minuteInt : minuteInt + "";
        String second = secondInt / 10 == 0 ? "0" + secondInt : secondInt + "";
        return year + "-" + month + "-" + day + " " + hour + ":" + month + ":" + second;
    }

    @Override
    public void index(String index, String id, String json) throws IOException {
        // 构建插入数据的Request
        final IndexRequest indexRequest = new IndexRequest();
        // 给Request对象封装索引，文档id，以及内容
        indexRequest.index(index).id(id).source(json, XContentType.JSON);
        // 发送给es
        final IndexResponse response = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);

        // 响应结果
        if (!CREATED.equals(response.getResult().getLowercase())) {
            // 添加失败
            log.error("【响应结果-搜索模块添加失败】 index={},id={},json={}", index, id, json);
            GraceException.display(ExceptionEnums.SEARCH_INDEX_ERROR);
        }
        log.info("【搜索模块添加成功】 index={},id={},json={}", index, id, json);
    }
}
